﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Threading;
using JESAI.Core.Extensions;
using JESAI.Core.Util.Extensions.Strings;

namespace JESAI.Core.Validate
{
    /// <summary>
    /// 校验上下文
    /// </summary>
    public abstract class ValidateContext
    {
        /// <summary>
        /// 错误提示信息
        /// </summary>
        public List<(string path, string error)> ErrorMessage = new List<(string path, string error)>();

        /// <summary>
        /// 子节点
        /// </summary>
        public List<ValidateContext> Children = new List<ValidateContext>();

        /// <summary>
        /// 父节点
        /// </summary>
        public ValidateContext Parent { get; set; }

        /// <summary>
        /// 校验属性名称
        /// </summary>
        public string ModelName { get; protected set; }

        private string _modelPath = string.Empty;
        /// <summary>
        /// 校验属性路径
        /// </summary>
        public string ModelPath
        {
            get
            {
                if (_modelPath.IsNullOrEmpty())
                {
                    //先获取前缀
                    var prefix = Parent?.ModelPath;
                    if (prefix.IsNullOrEmptyOrWhiteSpace())
                    {
                        _modelPath = ModelName;
                    }
                    else
                    {
                        if ((ModelName ?? "").StartsWith("["))
                        {
                            _modelPath += prefix + ModelName;
                        }
                        else
                        {
                            _modelPath += $"{prefix}.{ModelName}";
                        }
                    }
                }
                return _modelPath;
            }
        }
    }

    /// <summary>
    /// 校验上下文
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ValidateContext<T> : ValidateContext
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="model"></param>
        /// <param name="modelName"></param>
        internal ValidateContext(T model, string modelName)
        {
            Model = model;
            ModelName = modelName;
        }

        /// <summary>
        /// 校验模型
        /// </summary>
        public T Model { get; }

        /// <summary>
        /// 为某个属性开启校验
        /// </summary>
        /// <typeparam name="TProp"></typeparam>
        /// <param name="prop"></param>
        /// <returns></returns>
        public ValidateContext<TProp> RuleFor<TProp>(Expression<Func<T, TProp>> prop)
        {
            //获取prop的name
            var member = (prop.Body as MemberExpression).Member;
            var propName = member.Name;
            var attrs = member.GetCustomAttributes(typeof(ValidateDisplayNameAttribute), true);
            if (attrs.Length > 0)
            {
                var attr = attrs[0] as ValidateDisplayNameAttribute;
                if (attr.Name.IsNotNullOrEmptyOrWhiteSpace())
                {
                    propName = attr.Name;
                }
            }
            else
            {
                attrs = member.GetCustomAttributes(typeof(DisplayNameAttribute), true);
                if (attrs.Length > 0)
                {
                    var attr = attrs[0] as DisplayNameAttribute;
                    if (attr.DisplayName.IsNotNullOrEmptyOrWhiteSpace())
                    {
                        propName = attr.DisplayName;
                    }
                }
            }

            var propModel = prop.Compile()(Model);
            var newCtx = new ValidateContext<TProp>(propModel, propName);
            Children.Add(newCtx);
            newCtx.Parent = this;
            return newCtx;
        }

        /// <summary>
        /// 当前节点的名字
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public ValidateContext<T> WithDisplayName(string name)
        {
            ModelName = name;
            return this;
        }

        /// <summary>
        /// 如果校验失败就结束后面的校验
        /// </summary>
        /// <returns></returns>
        public ValidateContext<T> IfFailThenExit()
        {
            //检查是否出现已经校验失败,如果校验失败就直接放回
            var msg = ValidateModelHelper.FetchMessage(this);
            if (msg.IsNotNullOrEmptyOrWhiteSpace()) throw new ValidateException();
            return this;
        }

        /// <summary>
        /// 使用其他的校验逻辑去校验模型
        /// </summary>
        /// <param name="action"></param>
        public void UseValidateAction(Action<ValidateContext<T>> action)
        {
            action?.Invoke(this);
        }

        /// <summary>
        /// 有条件的校验
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="action"></param>
        public ValidateContext<T> When(Func<T, bool> predicate, Action<ValidateContext<T>> action)
        {
            var b = predicate?.Invoke(Model);
            if (b == true) action?.Invoke(this);
            return this;
        }

        /// <summary>
        /// 自定义校验规则(注意: 第一个func返回true时表示验证通过！)
        /// </summary>
        /// <param name="mustReturnTrue"></param>
        /// <param name="errorMessage"></param>
        public void CustomeValidate(Func<T, bool> mustReturnTrue, string errorMessage = null)
        {
            var b = mustReturnTrue?.Invoke(Model);
            if (b == false)
            {
                ErrorMessage.Add((ModelPath, errorMessage ?? $"'{ModelPath}' 校验失败!"));
            }
        }
    }
}
